Step 34: Validate ObjectID
We should be validating the input to Bookmark DAO operations. Namely, we should validate the ID parameter.
Add the following imports at the top of src/data/BookmarkDAO.js file:
import { z } from "zod";
import mongoose from "mongoose";
Update the following operation in the same file
// return the bookmark with the given id
// return null if resource does not exist in our database
// throws ApiError if id is invalid
async read(id) {
  try {
    z.string()
      .refine((id) => mongoose.isValidObjectId(id), {
        message: "Invalid ID!",
      })
      .parse(id);
    const bookmark = await Bookmark.findById(id);
    return bookmark;
  } catch (err) {
    throw new ApiError(400, err.message);
  }
}
Update the following tests in the tests/data/BookmarkDAO.test.js file”
it("test read() given invalid ID", async () => {
  try {
    await bookmarkDAO.read("invalid");
  } catch (err) {
    expect(err.status).toBe(400);
  }
});
it("test read() given valid but non-existing ID", async () => {
  const _bookmark = await bookmarkDAO.read(
    mongoose.Types.ObjectId().toString()
  );
  expect(_bookmark).toBeNull();
});
Let’s update the BookmarkDAO.js to validate object IDs for other operations too. First, refactor the code by adding the following helper function before the class declaration.
const validObjectId = z.string().refine((id) => mongoose.isValidObjectId(id), {
  message: "Invalid ID!",
});
Next, update the read operation:
// return the bookmark with the given id
// return null if resource does not exist in our database
// throws ApiError if id is invalid
async read(id) {
  try {
    validObjectId.parse(id);
    const bookmark = await Bookmark.findById(id);
    return bookmark;
  } catch (err) {
    throw new ApiError(400, err.message);
  }
}
Now update the delete and update operations and add tests for them!
Run all the tests and make sure they all pass. Then, save and commit changes.